<!-- 表单组件 -->
<template>
  <el-form
    ref="myForm"
    class="my-el-from"
    :model="formDatas"
    :label-width="labelWidth"
    :label-position="labelPosition"
    :show-message="elmShowMsg"
    :rules="rules"
    v-bind="$attrs"
  >
    <my-row :is-inline="isInline" :gutter="isInline ? gutter : 0" v-bind="$attrs">
      <my-col
        v-for="(item, index) in itemsDatas"
        :key="item.label + item.prop"
        :item-data="item"
        :is-grid="isGrid"
        :is-inline="isInline"
        v-bind="$attrs"
      >
        <!-- form里面需要分模块，目前设置为mouduleItems 数组或对象,该组件暂时无分模块功能，有需求可以增加改功能 -->
        <template v-if="item.type === 'divider' && Array.isArray(item.mouduleItems)">
          <slot v-if="item.slotName" :name="item.slotName" :item="item" />
          <div>{{ index }}</div>
        </template>
        <!-- 正常模块类型 -->
        <form-item v-else :is-inline="isInline" :item-data="item" :form-datas="formDatas" :validate-message-type="validateMessageType">
          <template v-if="item.type == 'custom'">
            <slot :name="item.prop" :item="item" :form-data="formDatas" />
          </template>
        </form-item>
      </my-col>
      <!-- 操作按钮 -->
      <el-col
        v-if="isInline"
        ref="operationEl"
        class="operation-style"
        :is-grid="isGrid"
        :is-inline="isInline"
        :class="[handleBtnPosition(), opertaionElNeedPadBottom ? 'padding-bottom-10' : '']"
        :xs="24"
        :sm="12"
        :md="8"
        :lg="8"
        :xl="6"
      >
        <slot />
      </el-col>
      <el-form-item v-else>
        <slot />
      </el-form-item>
    </my-row>
  </el-form>
</template>

<script>
import { defineComponent, computed, reactive, provide, ref, onMounted, toRefs, getCurrentInstance } from 'vue';
import { ItemDefCof } from './itemDefCof.js';
import FormItem from './MyItem.vue';
import MyRow from './MyRow.vue';
import MyCol from './MyCol.vue';

export default defineComponent({
  name: 'MyForm',
  components: { FormItem, MyRow, MyCol },
  props: {
    // 默认栅格式布局 xs = 24 sm = 12 md=12 lg=8 xl=6
    isGrid: { type: Boolean, default: true },
    // 栅格式布局 gutter, col间距
    gutter: { type: Number, default: 12 },
    // 表单生成数据
    itemsDatas: { type: [Array, Object], default: () => [] },
    // 表单数据
    // formDatas : { type : Object, default : () => {} },
    // label 宽度
    labelWidth: { type: String, default: '105px' },
    // label 位置
    labelPosition: { type: String, default: 'right' },
    // 是否是内联模式，非内联模式则会按照element的原型form一样，竖行排列,剔除掉栅格布局，isGrid，gutter将不起作用
    isInline: { type: Boolean, default: true },
    // 校验信息 显示模式，正常element模式，另一种和宇云外部提示模式 type: eleMsg, outMsg
    validateMessageType: { type: String, default: 'eleMsg' },
    // element 是否显示校验错误信息
    showMessage: { type: Boolean, default: true },
    modelValue: { type: Object, default: () => {} },
    rules: { type: Object, default: () => {} }
  },
  setup(props, context) {
    const state = reactive({
      itemDefCof: ItemDefCof,
      myForm: null, // 表单对象
      resetFormData: null, // 重置数据对象
      opertaionElNeedPadBottom: false // 最后操作栏是否需要padding-bottom（没有子元素就不需要）
    });
    provide('rootForm', {
      ...props,
      ...state
    });

    const myForm = ref();
    const formDatas = ref({});
    onMounted(() => {
      state.myForm = myForm;
      hangderOpertaiontEl();
      formDatas.value = props.modelValue;
      // 处理码表
      itemDatasTableCodeHandle(props.itemsDatas);
    });

    // 赋值表单，根据传入的对象值 (既可以赋值，也可以用作特殊情况下的重置表单， 配合clearValidate方法)
    const setFormDataToObj = (obj) => {
      const keys = Object.keys(props.formDatas);
      const formDatas = {};
      keys.forEach((key) => {
        formDatas[key] = obj[key] || props.formDatas[key];
      });
      Object.assign(props.formDatas, formDatas);
    };

    // 数据中tableCode处理
    const itemDatasTableCodeHandle = (newVal) => {
      const type = getDataType(newVal);
      let arr = [];
      if (type === 'Array') {
        arr = newVal.filter((item) => item.type === 'codeTable');
      } else if (type === 'Object') {
        Object.keys(newVal).forEach((key) => {
          if (newVal[key].type === 'codeTable') {
            newVal[key].codeKey = newVal[key].codeKey || newVal[key].prop;
            arr.push(newVal[key]);
          }
          return false;
        });
      } else {
        return;
      }
      if (arr.length > 0) {
        const { codeType, codeTypeExt } = getCodeTypeAndCodeTypeExt(arr);
        getCodeTableOptions(codeType, codeTypeExt, arr);
      }
    };
    const { proxy } = getCurrentInstance();
    const getCodeTableOptions = (codeType, codeTypeExt, codeItems) => {
      const hash = {};
      if (proxy && proxy.$getCode) {
        proxy.$getCode({ codeType }).then((res) => {
          //传入的配置项
          const { options } = res || {};
          codeItems.forEach((item) => {
            let codeKey = item.codeKey || item.prop;
            let itemData = res.data.data[codeKey.toUpperCase()];
            if (itemData && itemData.length) {
              const arr = itemData.map((v) => {
                return {
                  dispVal: v.dispVal || v.label || v[options?.labelKey],
                  dataVal: v.dataVal || v.value || v[options?.valueKey]
                };
              });
              if (item.filterFn) {
                this.$set(item, 'options', item.filterFn(itemData));
              } else if (item.collectionFilter) {
                // 过滤处理 collectionFilter 留下的值
                const collections = item.collectionFilter.split(',');
                let condition = (p) => (item.reverse ? !collections.includes(p.dataVal) : collections.includes(p.dataVal));
                item.options = itemData.filter((p) => condition(p));
              } else if (item.reverseFilter) {
                // reverseFilter 排除的值
                const collections = item.reverseFilter.split(',');
                let condition = (p) => (item.reverse ? collections.includes(p.dataVal) : !collections.includes(p.dataVal));
                item.options = itemData.filter((p) => condition(p));
              } else {
                item.options = arr;
              }
            } else {
              hash[codeKey] = codeKey;
            }
          });
        });
      }
    };
    // 获取codekey和codeTypeExt
    const getCodeTypeAndCodeTypeExt = (arr) => {
      let codeType = '';
      const codeTypeExt = [];
      arr.forEach((k) => {
        let item = k.type === 'codeTable' ? k : '';
        if (getDataType(codeType) === 'Object') {
          codeTypeExt.push(item.codeKey || item.prop);
        } else {
          codeType += (item.codeKey || item.prop) + ',';
        }
      });
      codeType = codeType.substring(0, codeType.length - 1);
      return {
        codeType,
        codeTypeExt
      };
    };
    // 判断数据为对象
    const getDataType = (data) => {
      if (data instanceof Array) {
        return 'Array';
      } else if (data instanceof Object) {
        return 'Object';
      } else {
        return 'param不是对象类型';
      }
    };

    // 按钮位置处理
    const handleBtnPosition = () => {
      const itemLength = props.itemsDatas.length;
      if (props.isGrid) {
        return 'handle-right';
      } else {
        // 如果是弹框内部的，不用响应式，则两个以内的不做处理，大于两个则靠右
        if (itemLength <= 2) {
          return '';
        }
        return 'handle-right';
      }
    };
    // 对该表单项进行重置，将其值重置为初始值并移除校验结果
    const resetFields = () => {
      state.myForm.resetFields();
    };
    // 移除该表单项的校验结果
    const clearValidate = () => {
      state.myForm.clearValidate();
    };

    // 按钮位置处理
    const hangderOpertaiontEl = () => {
      const operationEl = ref(null);
      if (operationEl.value && operationEl.value.$children.length > 0) {
        state.opertaionElNeedPadBottom = true;
      } else {
        state.opertaionElNeedPadBottom = false;
      }
    };

    // 表单校验
    const validate = (callback = function () {}) => {
      myForm.value.validate((prop, isValid) => {
        callback(prop, isValid);
      });
    };

    // 提示信息处理
    const elmShowMsg = computed(() => {
      // 校验信息 显示模式，正常element模式
      if (props.validateMessageType === 'eleMsg') {
        return props.showMessage;
      } else {
        return false;
      }
    });

    // 暴露方法，供外部调用，也可定义emits:['validate','resetFields']
    context.expose({ validate, resetFields });
    return {
      ...toRefs(state),
      getDataType,
      resetFields,
      clearValidate,
      hangderOpertaiontEl,
      setFormDataToObj,
      getCodeTableOptions,
      getCodeTypeAndCodeTypeExt,
      handleBtnPosition,
      elmShowMsg,
      formDatas
    };
  }
});
</script>

<style lang="scss" scoped>
.handle-right {
  float: right;
  text-align: right;
}

.padding-bottom-10 {
  padding-bottom: 10px;
}

.light {
  .handle-right {
    padding-bottom: 0;
  }
}

.inline {
  display: inline-block;
  vertical-align: top;
}

.moudule-items {
  margin-top: 5px;
}

.inline-moudule-items {
  margin-top: 5px;
  border: 1px solid #dcdfe6;
  border-top: none;
  border-radius: 3px;
}

.not-last-moudule-items {
  margin-bottom: 16px;
}

.operation-style {
  max-width: 100%;
  flex: 1;
}
</style>
